﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "DesignInterface.h"
#include "UObject/Object.h"
#include "AdapterPattern.generated.h"

/**	适配器模式 Adapter Pattern
 *	描述
 *		将一个接口转换成客户希望的另一个接口，适配器模式使接口不兼容的那些类可以一起工作，其别名为包装器(Wrapper)。
 *	套路
 *		Target（目标抽象类）
 *			目标抽象类定义了客户所需要的接口，可以是一个抽象类或接口，也可以是一个具体的类。
 *		Adapter（适配器类）
 *			适配器可以调用另一个接口，作为一个转换器，对Adaptee和Target进行适配。适配器类是适配者模式的核心，在适配器模式中，它通过继承Target并关联一个Adaptee对象使二者产生联系。
 *		Adaptee（适配者类）
 *			适配者即被适配的角色，它定义了一个已经存在的接口，这个接口需要适配，一般是一个具体类，包含了客户希望使用的业务方法，在某些情况下可能没有适配者类的源代码。
 *	使用场景
 *		系统需要使用现有的类，而这些类的接口不符合系统的需要。
 *		想要建立一个可以重复使用的类，用于与一些彼此之间没有太大关联的一些类，包括一些可能在将来引进的类一起工作。
 *		示例
 *			为了处理项目代码更新后与原来接口不兼容，可以创建适配器来保证“旧调新”、“新调旧”的功能需求。
 *			已定下接口后，要求调用第三方SDK等（类似于电源适配器，要求输出12V，但是输入220V）
 *	优缺点
 *		优点
 *			将目标类和适配者类解耦，通过引入一个适配器类来重用现有的适配者类，而无须修改原有代码。
 *			增加了类的透明性和复用性，将具体的实现封装在适配者类中，对于客户端类来说是透明的，而且提高了适配者的复用性。
 *			灵活性和扩展性都非常好，通过使用配置文件，可以很方便地更换适配器，也可以在不修改原有代码的基础上增加新的适配器类，完全符合“开闭原则”。
 *		缺点
 *			过多的使用适配器，会让系统非常零乱，不易整体进行把握
 **/


UCLASS() // 适配者类 —— ffmpeg
class MISCELLANEOUSPROJECT_API Uffmpeg : public UObject
{
	GENERATED_BODY()

public:
	virtual void OpenFile(const FString& Filepath)
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" use ffmpeg sdk to play media"));
	}
};

UCLASS() // 适配者类 —— VLC
class MISCELLANEOUSPROJECT_API UVLC : public UObject
{
	GENERATED_BODY()

public:
	virtual void OpenFile(const FString& Filepath)
	{
		// UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" use VLC sdk to play media"));
	}
};

UCLASS() // 适配器类 —— UffmpegAdapter
class MISCELLANEOUSPROJECT_API UffmpegAdapter : public UObject, public IMediaInterface
{
	GENERATED_BODY()

public:
	UPROPERTY()
	Uffmpeg* m_pffmpegSDK;

	UffmpegAdapter()
	{
		m_pffmpegSDK = NewObject<Uffmpeg>();
	}

	~UffmpegAdapter() {}

	virtual void PlayVideo(const FString& Filepath) override
	{
		m_pffmpegSDK->OpenFile(Filepath);
	}
};

UCLASS() // 适配器类 —— UVLCAdapter
class MISCELLANEOUSPROJECT_API UVLCAdapter : public UObject, public IMediaInterface
{
	GENERATED_BODY()

public:
	UPROPERTY()
	UVLC* m_pVLCSDK;

	UVLCAdapter()
	{
		m_pVLCSDK = NewObject<UVLC>();
	}

	~UVLCAdapter() {}

	virtual void PlayVideo(const FString& Filepath) override
	{
		m_pVLCSDK->OpenFile(Filepath);
	}
};

UCLASS() // 调用测试
class MISCELLANEOUSPROJECT_API AAdapterTestActor : public AActor
{
	GENERATED_BODY()
protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override
	{
		// 使用 ffmpegAdapter 适配器
		IMediaInterface* MediaPlayer = Cast<IMediaInterface>(NewObject<UffmpegAdapter>());
		MediaPlayer->PlayVideo(TEXT("C:/浪客剑心.最终章.人诛篇.mp4"));

		// 使用 VLCAdapter 适配器
		MediaPlayer = Cast<IMediaInterface>(NewObject<UVLCAdapter>());
		MediaPlayer->PlayVideo(TEXT("C:/浪客剑心.最终章.人诛篇.mp4"));
	}
};

